
#include "../detail/thread.hpp"

namespace mtl {

  bool operator==(const thread::id& x, const thread::id& y) {
    return thread::equals(x.m_h, y.m_h);
  }

  bool operator!=(const thread::id& x, const thread::id& y) {
    return !(x == y);
  }

  bool operator<(const thread::id& x, const thread::id& y) {
    return x.m_h < y.m_h; // 微妙... いいのか？これ．
  }

  bool operator<=(const thread::id& x, const thread::id& y) {
    return !(y < x);
  }

  bool operator>(const thread::id& x, const thread::id& y) {
    return y < x;
  }

  bool operator>=(const thread::id& x, const thread::id& y) {
    return !(x < y);
  }

  void thread::join() {
    if (get_id() == this_thread::get_id()) {
      throw system_error(
          error_code(resource_deadlock_would_occur, system_category()),
          "same thread.");
    }
    thread_context_ptr const lcontext = get_context_ptr();
    if (!lcontext) {
      throw system_error(
          error_code(invalid_argument, system_category()),
          "not joinable.");
    }

    bool do_join = false;
    {
      lock_guard<mutex> lock(lcontext->m_mtx);
      if (lcontext->m_joined) {
        return;
      }
      while (!lcontext->m_done) {
        lcontext->m_done_cond.wait(lock);
      }
      do_join = true;
      lcontext->m_joined = true;  // 他 thread から join 呼び出しさせないため
    }
    if (do_join) {
      // リソース解放のため 1 回は呼ばなければならない
      void* ret;
      PTHREAD_VALIDATE(
        pthread_join(lcontext->m_handle, &ret), "failed to join");
      lock_guard<mutex> lock(lcontext->m_mtx);
      lcontext->m_handle = thread_context::invalid_native_handle;
    }

    lock_guard<mutex> lock(m_context_mutex);
    if (lcontext == m_context_ptr) {
      // context を使えなくする
      m_context_ptr.reset();
    }
  }

  namespace this_thread {
    thread::id get_id() {
      return thread::id(pthread_self());
    }

    void yield() {
      pthread_yield();
    }

    /*template<class Clock, class Duration>
      void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);

    template<class Rep, class Period>
      void sleep_for(const chrono::duration<Rep, Period>& rel_time);*/

    // not included in c++0x

    void check_cancel() {
      pthread_testcancel();
    }
  }

}

